package com.mail;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.mail.BodyPart;
import javax.mail.Flags;
import javax.mail.Flags.Flag;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.search.FlagTerm;

public class GmailClient {
	
	private static Session session;
	
	private static int WAIT_FOR_EMAIL_SECONDS = 30;
	
	static{
		
		Properties props = System.getProperties();
		props.setProperty("mail.store.protocol", "imaps");
		
		session = Session.getDefaultInstance(props, null);
	}
	
	private Store store;
	
	public GmailClient(String email, String password){
		try {
			store = session.getStore("imaps");
			store.connect("imap.gmail.com", email, password);

		} catch (MessagingException e) {
			throw new IllegalStateException(String.format("Could not connect to to gmail with user '%s'/'%s'", email, password),e);
		}
		
	}
	
	public Message[] getUnreadMessages(){
		
		try {
			Folder inbox = store.getFolder("INBOX");
			inbox.open(Folder.READ_WRITE);
			FlagTerm ft = new FlagTerm(new Flags(Flags.Flag.SEEN), false);
		    return inbox.search(ft);
		
		} catch (MessagingException e) {
			throw new IllegalStateException("Couldn't get gmail unread messages",e);
		}
	}
	
	public Message[] getMessages(){
		try {
			Folder inbox = store.getFolder("INBOX");
			inbox.open(Folder.READ_WRITE);
			return inbox.getMessages();
		
		} catch (MessagingException e) {
			throw new IllegalStateException("Couldn't get gmail messages",e);
		}
	}
	
	public Message waitForNewMessage(String subject){
		
		Message message = null;
		
		try{
		
			long start = new Date().getTime();
			
			long waitUntil = start + WAIT_FOR_EMAIL_SECONDS * 1000;
			
			while(new Date().getTime() < waitUntil && message == null){
				
				Message[] messages = getUnreadMessages();
				
				int i = 0;
				
				while (i < messages.length && message == null){
					
					Message msg = messages[i];
					
					if(msg.getSubject().equals(subject)){
						
						message = msg;
					}
					else{
						i++;
					}
				}
				if(message == null){
					
					Thread.sleep(2000);
				}
			}
		}catch(Exception e){
			
			throw new IllegalStateException("Couldn't get new message", e);
		}	
		if(message != null){
				
			return message;
		}
		else
			throw new IllegalStateException(String.format("Time out after '%s' segs expecting for email subject '%s'", WAIT_FOR_EMAIL_SECONDS, subject));	
	}
	
	public List<Message> getMessagesWithSubject(String subject){
	
		Message[] messages = getMessages();
		
		List<Message> messagesList = new ArrayList<Message>();
		
		try{
			
			for (int i = 0; i < messages.length; i++) {
				
				Message message = messages[i];
				
				if(message.getSubject().equals(subject)){
					messagesList.add(message);
				}
			}
			return messagesList;
		}catch (MessagingException e) {
			throw new IllegalStateException("Couldn't get gmail message subject",e);
		}
		
	}
	
	public static String getHtmlContent(Message message){
		
		String content = "";
		
		try{
			Multipart parts = (Multipart) message.getContent();
		    
			for(int i = 0; i < parts.getCount(); i++){
				 
				BodyPart part = parts.getBodyPart(i);
			      
			    content += part.getContent().toString();
			}
			
		}catch(Exception e){
			
			throw new IllegalStateException("Error getting message content", e);
		}
		return content;
	}
	
	 public static String getLinkMessage(Message message, String partialLink){
		
		 String link = null;
		 
		 try{
			
			 Pattern pattern = Pattern.compile("a.*>.*" + partialLink + ".*");
			 
			 Multipart parts = (Multipart) message.getContent();
			    
			 int i = 0;
			 
			 while (i < parts.getCount() && link == null){
				 
			     BodyPart part = parts.getBodyPart(i);
			      
			     String content = part.getContent().toString();
			 
			     String[] lines = content.split("<");
			     
			     int j = 0;
			     
			     while(j < lines.length && link == null){
			    	 
			    	 String thisLine = lines[j];
			     
			    	 Matcher m = pattern.matcher(thisLine);
			        	
		        	 if (m.find()){
		        		 
		        		link = thisLine.split(">")[1];
		        	 }
		        	 else{
		        		 j++;
		        	 }
			     }
			     
			     if(link == null){
			    	 i++;
			    }
			}
			 
	        if(link != null){
	              
	        	return link;
	        
	        }
	        else
	        	throw new IllegalStateException(String.format("Couldn't find partialLink '%s' in message", partialLink)); 
	    }
	    catch (Exception e){
	      
	    	throw new IllegalStateException("Error finding link in message", e);
	    }
	    
	 }

	public static void markAsRead(Message email) {
		
		try {
			email.setFlag(Flag.SEEN, true);
			
		} catch (MessagingException e) {
			throw new IllegalStateException("Error marking message as read", e);
		} 
	}
}
